﻿Imports System.Threading.Tasks
Imports SpeechExceptionsToolkit.Core
Imports DynamicVCD.Core.Entities
Imports MSSpeech = Windows.Phone.Speech.VoiceCommands
Imports Windows.Storage.Streams
Imports Windows.Storage
Imports Windows.Foundation

Public NotInheritable Class VoiceCommandService

    Private Sub New()

    End Sub

    Private Const VCDFileName As String = "vcd.xml"
    Private Const XmlHeader As String = "<?xml version=""1.0"" encoding=""utf-8""?>"

    Public Shared Async Function InstallVoiceCommandDefinitionAsync(voiceCommandDefinition As VoiceCommandDefinition) As Task
        If voiceCommandDefinition Is Nothing Then Throw New ArgumentNullException("voiceCommandDefinition")
        Try
            Dim xmlString = CreateXml(voiceCommandDefinition)
            If Await SaveAsync(VCDFileName, xmlString) Then
                Await MSSpeech.VoiceCommandService.InstallCommandSetsFromFileAsync(GetLocalUri(VCDFileName))
            End If
        Catch ex As Exception
            Dim newEx = ExceptionFactory.CreateException(ex)
            Throw newEx
        End Try
    End Function

    Public Shared Function InstallCommandSetsFromFileAsync(voiceCommandDefinitionUri As System.Uri) As IAsyncAction
        Try
            Return MSSpeech.VoiceCommandService.InstallCommandSetsFromFileAsync(voiceCommandDefinitionUri)
        Catch ex As System.Exception
            Dim newEx = ExceptionFactory.CreateException(ex)
            Throw newEx
        End Try
    End Function

    Public Shared ReadOnly Property InstalledCommandSets As System.Collections.Generic.IReadOnlyDictionary(Of String, Windows.Phone.Speech.VoiceCommands.VoiceCommandSet)
        Get
            Return MSSpeech.VoiceCommandService.InstalledCommandSets
        End Get
    End Property

    Private Shared Function GetLocalUri(fileName As String) As System.Uri
        Dim strUrl = String.Format("ms-appdata:///local/{0}", fileName)
        Return New System.Uri(strUrl, UriKind.RelativeOrAbsolute)
    End Function

    Private Shared Async Function SaveAsync(filename As String, xmlString As String) As Task(Of Boolean)
        Dim result = True
        Try
            Dim localFolder = ApplicationData.Current.LocalFolder
            Dim storageFile = Await localFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting)
            Using fs = Await storageFile.OpenAsync(FileAccessMode.ReadWrite)
                Using outStream = fs.GetOutputStreamAt(0)
                    Using dataWriter = New DataWriter(outStream)
                        If xmlString IsNot Nothing Then dataWriter.WriteString(xmlString)
                        Await dataWriter.StoreAsync()
                        dataWriter.DetachStream()
                    End Using
                End Using
            End Using
        Catch ex As Exception
            result = False
        End Try
        Return result
    End Function

    Private Shared Async Function LoadAsync(filename As String) As Task(Of String)
        Dim xml As String = Nothing
        Try
            Dim localFolder = ApplicationData.Current.LocalFolder
            Dim storageFile = Await localFolder.GetFileAsync(filename)
            Using fs = Await storageFile.OpenAsync(FileAccessMode.Read)
                Using inStream = fs.GetInputStreamAt(0)
                    Using reader = New DataReader(inStream)
                        Await reader.LoadAsync(CType(fs.Size, UInteger))
                        xml = reader.ReadString(CType(fs.Size, UInteger))
                        reader.DetachStream()
                    End Using
                End Using
            End Using
        Catch ex As Exception
            xml = Nothing
        End Try
        Return xml
    End Function

    Private Shared Function CreateXml(voiceCommandDefinition As VoiceCommandDefinition) As String
        If voiceCommandDefinition Is Nothing Then Throw New ArgumentNullException()
        Dim xElem = voiceCommandDefinition.GetXml()
        Dim xmlString = String.Format("{0}{1}", XmlHeader, xElem)
        Return xmlString
    End Function

End Class
